#include <stdio.h>
#include "Image.h"
#include "Class.h"
#include "CodeMethod.h"
#include "bootstrap.h"
#include "InterpretPrescription.h"
#include "Repl.h"
#include "util.h"
#include <fstream>

#define t_assert(test,name) \
   printf("%s ",name);   \
   if(test){ printf("[PASSED]\n");}else{printf("[FAILED]\n");};

#define t_asserteq(a,b,name) \
   {printf("%s ",name);   \
   int ar=a;int br=b;\
   if(ar==br){ printf("[PASSED]\n");}else{printf("[FAILED]\n");printf("A is %d and B is %d.\n",ar,br);};};
void repl(Image* image);
void factorial(Image* image,Class* cls){
    //factorial
   CodeMethod* factorial=new CodeMethod(image,"factorial",cls);
   InterpretPrescription* zeroFactorial=new InterpretPrescription();
   zeroFactorial->add(ast_return(ast_const(makeInteger(image,1))));
   InterpretPrescription* recurse=new InterpretPrescription();
   //^self*((self-1) factorial)
   recurse->add(ast_return(
           ast_message(ast_self(),"*:",1,
                ast_message(ast_message(ast_self(),"-:",1,ast_const(makeInteger(image,1))),"factorial",0)
                )
           )
      );
   factorial->add(
           ast_return(ast_message(ast_message(ast_self(),"=:",1,ast_const(makeInteger(image,0))),
                "ifTrue:else:",2,ast_closure(zeroFactorial),ast_closure(recurse)
           ))
       );
}
void runfile(string name,Repl& repl){
    ifstream stream(name.c_str());
    if(stream.fail()){
        printf("ERROR: Could not open file %s.\n",name.c_str());
    }else{
        repl.run(stream);
    }
}
int main(){
   printf("Tests started\n");
   //image and base classes
   Image* image=new Image();
   bootstrap(image);
   t_assert(image!=NULL,"Image created");

   //factorial
   factorial(image,image->clsInteger);
   Object* factorial=makeInteger(image,6)->send(image,"factorial",0,NULL);
   t_asserteq(inspectInteger(factorial),720,"Testing factorial");

   Repl::prepareImage(image);
   Repl repl(image);
   runfile("../msrc/Bootstrap.mts",repl);
   runfile("../msrc/Array.mts",repl);
   runfile("../msrc/Vector.mts",repl);
   runfile("../msrc/XClass.mts",repl);
   runfile("../msrc/String.mts",repl);
   runfile("../msrc/Boolean.mts",repl);
   runfile("../msrc/Ref.mts",repl);
   runfile("../msrc/Integer.mts",repl);
   runfile("../msrc/Range.mts",repl);
   runfile("../msrc/StringBuffer.mts",repl);
   runfile("../msrc/Mixin.mts",repl);
   runfile("../msrc/Collections.mts",repl);
   repl.run();
}